#include "raft_middleware/RaftMiddleware.h"

#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>

#include <memory>
#include <string>

#include "raft_middleware/rpc_proto/middleware_rpc.grpc.pb.h"
#include "raft_middleware/rpc_proto/middleware_rpc.pb.h"
#include "raft_utils/Config.h"

raft::middleware::RaftMiddleware::RaftMiddleware(std::shared_ptr<utils::Command> command)
    : command_(std::move(command)),
      is_search_(false),
      log(bq::log::get_log_by_name(utils::Config::getInstance()->get_log_name())) {

    write_address_ = utils::Config::getInstance()->get_raft_core_ip() + ":" + std::to_string(utils::Config::getInstance()->get_raft_core_port());
    search_address_ = utils::Config::getInstance()->get_raft_core_ip() + ":" + std::to_string(utils::Config::getInstance()->get_state_machine_rpc_port());

    log.debug("[func-raft::middleware::RaftMiddleware::RaftMiddleware] write_address_: {}", write_address_);
    log.debug("[func-raft::middleware::RaftMiddleware::RaftMiddleware] search_address_: {}", search_address_);

    auto write_channel = grpc::CreateChannel(write_address_, grpc::InsecureChannelCredentials());
    write_stub_ = middleware_rpc_proto::MiddlewareService::NewStub(write_channel);

    auto serach_channel = grpc::CreateChannel(search_address_, grpc::InsecureChannelCredentials());
    search_stub_ = middleware_rpc_proto::MiddlewareService::NewStub(serach_channel);
}

std::string raft::middleware::RaftMiddleware::recv_msg(const std::string& msg) {
    log.verbose("Start: void raft::middleware::RaftMiddleware::recv_msg(const std::string &msg)");

    processing_command(msg);
    auto result = send_command();
    log.info("[func-raft::middleware::RaftMiddleware::recv_msg] result: {}", result);

    log.verbose("End: void raft::middleware::RaftMiddleware::recv_msg(const std::string &msg)");
    return result;
}

std::string raft::middleware::RaftMiddleware::send_command() {
    log.verbose("Start: std::string raft::middleware::RaftMiddleware::send_command()");

    while (true) {
        auto request = std::make_shared<middleware_rpc_proto::ExecuteCommand>();
        request->set_apply_msg(command_->as_string());
        auto reply = std::make_shared<middleware_rpc_proto::ExecuteCommandReply>();
        grpc::Status status;
        grpc::ClientContext context;
        // 选择正确的 stub 和地址
        auto& stub = is_search_ ? search_stub_ : write_stub_;
        auto& address = is_search_ ? search_address_ : write_address_;

        // 执行 RPC 调用
        status = stub->execute_command(&context, *request, reply.get());

        if (!status.ok()) {
            log.warning("[func-raft::middleware::RaftMiddleware::send_command()] rpc failed. rpc request address: {}", address);
            continue;
        }

        if (!reply->is_success()) {
            log.debug("[func-raft::middleware::RaftMiddleware::send_command()] rpc succeeded but this node is not the leader");
            address = reply->result();
            auto channel = grpc::CreateChannel(address, grpc::InsecureChannelCredentials());
            stub = middleware_rpc_proto::MiddlewareService::NewStub(channel);
        } else {
            log.verbose("End: std::string raft::middleware::RaftMiddleware::send_command()");
            return reply->result();
        }
    }
}